home *** CD-ROM | disk | FTP | other *** search
- /*------------------------------------------------------------------------------
- #
- # MBTaskSample.c
- #
- # derived from MPW 3.1's "Sample", a MultiFinder-Aware Simple Sample Application
- # - and nearly the same thing as the "TaskSample" in the neighbour folder.
- #
- # Launch "MBTaskSample" first, and then "Exercise", and do A/ROSE parallel processing
- # (or rather: Program-to-program communication) even without MCP card!
- #
- # Components:
- # MBTaskSample.c
- # MBTaskSample.r
- # MBTaskSample.h
- # ITER16.a
- # MBTaskSample.make
- #
- # MPW build commands:
- #
- C MBTaskSample.c -r
- Link MBTaskSample.c.o ∂
- ITER16.a.o ∂
- "{CLibraries}"CRuntime.o ∂
- "{CLibraries}"CInterface.o ∂
- "{Libraries}"Interface.o ∂
- ::IPCGlue.o ∂
- -o MBTaskSample
- Rez -rd -o MBTaskSample MBTaskSample.r -append
- #
- #
- ------------------------------------------------------------------------------*/
-
-
-
- #include <Types.h>
- #include <Resources.h>
- #include <QuickDraw.h>
- #include <Fonts.h>
- #include <Events.h>
- #include <Windows.h>
- #include <Menus.h>
- #include <TextEdit.h>
- #include <Dialogs.h>
- #include <Desk.h>
- #include <ToolUtils.h>
- #include <Memory.h>
- #include <SegLoad.h>
- #include <Files.h>
- #include <OSUtils.h>
- #include <OSEvents.h>
- #include <DiskInit.h>
- #include <Packages.h>
- #include <Traps.h>
- #include <Strings.h>
- #include "MBTaskSample.h" // bring in all the #defines for MBTaskSample
-
-
- //---------------------------------------------------------------------------
- // A/ROSE declarations (from "os.h"):
-
- typedef long tid_type;
-
- struct mMessage
- {
- struct mMessage *mNext;
- long mId;
- short mCode;
- short mStatus;
- unsigned short mPriority;
- tid_type mFrom;
- tid_type mTo;
- unsigned long mSData [3];
- unsigned long mOData [3];
- long mDataSize; // Size of data buffer in bytes. set to negative
- // size of buffer if buffer is shared
- // between tasks. eg. Buffer cannot be copied
- char *mDataPtr;
- };
-
- typedef struct mMessage mMessage;
-
- // and #define's from "managers.h":
-
- #define OS_UNKNOWN_MESSAGE (1<<8) // unknown message
- #define Machine_Visible 0 // Register_task Machine visible flag
- //---------------------------------------------------------------------------
-
- // global variables
-
- SysEnvRec gMac; // set up by Initialize
- Boolean gHasWaitNextEvent; // set up by Initialize
- Boolean gInBackground; // maintained by Initialize and DoEvent
- long gSleepVal; // MultiFinder sleep value
- // for WaitNextEvent
-
- short gSent; // number of received/sent messages
- long gTID; // my task identifier returned by OpenQueue()
- WindowPtr gMyWindow; // only one window
-
- // Prototypes for parameter type checking.
-
- void EventLoop( void );
- void DoEvent( EventRecord *event );
- void DoUpdate( WindowPtr window );
- void DoActivate( WindowPtr window, Boolean becomingActive );
- void DoContentClick( WindowPtr window );
- void DrawWindow( WindowPtr window );
- void AdjustMenus( void );
- void DoMenuCommand( long menuResult );
- Boolean DoCloseWindow( WindowPtr window );
- void Terminate( void );
- void Initialize( void );
- void ForceEnvirons( void );
- Boolean IsAppWindow( WindowPtr window );
- Boolean IsDAWindow( WindowPtr window );
- Boolean TrapAvailable( short tNumber, TrapType tType );
- void AlertUser( short error );
- void BigBadError( short error );
- void NumToHex( long n, short d, char *s);
- short AROSEPrep();
- void TaskProcessing();
- void myBitSet(char *pixStorage, long i);
-
- extern pascal short ITER16(short cx, short cy, short nmax);
-
-
- // A/ROSE prototypes (from "os.h"):
-
- extern tid_type OpenQueue(void (*)());
- extern void CloseQueue();
- extern char Register_Task(char *, char *, short);
- extern void FreeMsg(mMessage *);
- extern void Send(mMessage *);
- extern mMessage *Receive(unsigned long, tid_type, unsigned short, long, ...);
- extern void SwapTID(mMessage *);
- extern char *AROSEGetMem();
- extern void AROSEFreeMem();
- extern short NetCopy();
-
-
-
- extern void _DataInit();
-
-
-
- #pragma segment Main
- main()
- {
- UnloadSeg((Ptr) _DataInit); // note that _DataInit must not be in Main!
-
- MaxApplZone(); // expand the heap so code segments load at the top
-
- Initialize(); // initialize the program
- UnloadSeg((Ptr) Initialize); // note that Initialize must not be in Main!
-
- EventLoop(); // call the main event loop
- }
-
-
- #pragma segment Main
- void EventLoop()
- {
- Boolean gotEvent;
- EventRecord event;
-
- do {
- gotEvent = WaitNextEvent(everyEvent, &event, gSleepVal, nil);
- if ( gotEvent )
- DoEvent(&event);
-
- //=========================
- TaskProcessing(); // <<<<<<<<<< this is the A/ROSE task !
- //=========================
-
- } while ( true ); // loop forever; we quit via Terminate/ExitToShell
- } //EventLoop
-
-
- #pragma segment Main
- void DoEvent(event)
- EventRecord *event;
- {
- short part, err;
- WindowPtr window;
- char key;
- Point aPoint;
-
- switch ( event->what ) {
- case mouseDown:
- part = FindWindow(event->where, &window);
- switch ( part ) {
- case inMenuBar: // process a mouse menu command (if any)
- AdjustMenus();
- DoMenuCommand(MenuSelect(event->where));
- break;
- case inSysWindow: // let the system handle the mouseDown
- SystemClick(event, window);
- break;
- case inContent:
- if ( window != FrontWindow() ) {
- SelectWindow(window);
- } else
- DoContentClick(window);
- break;
- case inDrag: // pass screenBits.bounds to get all gDevices
- DragWindow(window, event->where, &qd.screenBits.bounds);
- break;
- }
- break;
- case keyDown:
- case autoKey: // check for menukey equivalents
- key = event->message & charCodeMask;
- if ( event->modifiers & cmdKey ) // Command key down
- if ( event->what == keyDown ) {
- AdjustMenus(); // enable/disable/check menu items properly
- DoMenuCommand(MenuKey(key));
- }
- break;
- case activateEvt:
- DoActivate((WindowPtr) event->message, (event->modifiers & activeFlag) != 0);
- break;
- case updateEvt:
- DoUpdate((WindowPtr) event->message);
- break;
- case diskEvt:
- if ( HiWord(event->message) != noErr ) {
- SetPt(&aPoint, kDILeft, kDITop);
- err = DIBadMount(aPoint, event->message);
- }
- break;
- case kOSEvent:
- switch ((event->message >> 24) & 0x0FF) { // high byte of message
- case kSuspendResumeMessage: // suspend/resume is also an activate/deactivate
- gInBackground = (event->message & kResumeMask) == 0;
- DoActivate(FrontWindow(), !gInBackground);
- break;
- }
- break;
- }
- } //DoEvent
-
-
- #pragma segment Main
- void DoUpdate(window)
- WindowPtr window;
- {
- if ( IsAppWindow(window) ) {
- BeginUpdate(window); // this sets up the visRgn
- if ( ! EmptyRgn(window->visRgn) ) // draw if updating needs to be done
- DrawWindow(window);
- EndUpdate(window);
- }
- } //DoUpdate
-
-
- #pragma segment Main
- void DoActivate(window, becomingActive)
- WindowPtr window;
- Boolean becomingActive;
- {
- if ( IsAppWindow(window) ) {
- if ( becomingActive )
- ; // do whatever you need to at activation
- else
- ; // do whatever you need to at deactivation
- }
- } //DoActivate
-
- #pragma segment Main
- void DoContentClick(window)
- WindowPtr window;
- {
- #pragma unused (window)
- // do you want to do something here ?
- } //DoContentClick
-
-
- #pragma segment Main
- void DrawWindow(window)
- WindowPtr window;
- {
- Str255 s;
- Rect countRect;
- GrafPtr savePort;
- short xPos;
-
- GetPort(&savePort);
-
- SetPort(window);
-
- GetIndString(s, rWndStrings, 1);
- xPos = StringWidth(s) + 10;
-
- SetRect(&countRect, xPos+20, 20, xPos+80, 45);
- EraseRect(&countRect);
-
- MoveTo(20, 40);
- DrawString(s);
-
- MoveTo(xPos+25, 40);
- NumToString(gSent, s);
- DrawString(s);
-
- SetPort(savePort);
-
- } //DrawWindow
-
-
- #pragma segment Main
- void AdjustMenus()
- {
- WindowPtr window;
- MenuHandle menu;
-
- window = FrontWindow();
-
- menu = GetMHandle(mEdit);
- if ( IsDAWindow(window) ) { // a desk accessory might need the edit menu…
- EnableItem(menu, iUndo);
- EnableItem(menu, iCut);
- EnableItem(menu, iCopy);
- EnableItem(menu, iClear);
- EnableItem(menu, iPaste);
- } else { // …but we don’t use it
- DisableItem(menu, iUndo);
- DisableItem(menu, iCut);
- DisableItem(menu, iCopy);
- DisableItem(menu, iClear);
- DisableItem(menu, iPaste);
- }
- menu = GetMHandle(mSleep);
- if (gSleepVal == 0) {
- CheckItem(menu,iNoSleep,true);
- CheckItem(menu,i60Ticks,false);
- }
- else {
- CheckItem(menu,iNoSleep,false);
- CheckItem(menu,i60Ticks,true);
- }
- } //AdjustMenus
-
-
- #pragma segment Main
- void DoMenuCommand(menuResult)
- long menuResult;
- {
- short menuID; // the resource ID of the selected menu
- short menuItem; // the item number of the selected menu
- short itemHit;
- Str255 daName;
- short daRefNum;
- Boolean handledByDA;
- GrafPtr savePort;
-
- menuID = HiWord(menuResult); // use macros for efficiency to...
- menuItem = LoWord(menuResult); // get menu item number and menu number
- switch ( menuID ) {
- case mApple:
- switch ( menuItem ) {
- case iAbout: // bring up alert for About
- itemHit = Alert(rAboutAlert, nil);
- break;
- default: // all non-About items in this menu are DAs
- // type Str255 is an array in MPW 3
- GetItem(GetMHandle(mApple), menuItem, daName);
- daRefNum = OpenDeskAcc(daName);
- break;
- }
- break;
- case mFile:
- switch ( menuItem ) {
- case iReset:
- gSent = 0;
- GetPort(&savePort); // force redraw
- SetPort(gMyWindow);
- InvalRect(&(gMyWindow->portBits.bounds));
- SetPort(savePort);
-
- break;
- case iQuit:
- Terminate();
- break;
- }
- break;
- case mEdit: // call SystemEdit for DA editing & MultiFinder
- handledByDA = SystemEdit(menuItem-1); // since we don’t do any Editing
- break;
- case mSleep:
- switch ( menuItem ) {
- case iNoSleep:
- gSleepVal = 0;
- break;
- case i60Ticks:
- gSleepVal = 60;
- break;
- }
- break;
- }
- HiliteMenu(0); // unhighlight what MenuSelect (or MenuKey) hilited
- } //DoMenuCommand
-
-
-
- #pragma segment Main
- Boolean DoCloseWindow(window)
- WindowPtr window;
- {
- if ( IsDAWindow(window) )
- CloseDeskAcc(((WindowPeek) window)->windowKind);
- else if ( IsAppWindow(window) )
- CloseWindow(window);
- return true;
- } //DoCloseWindow
-
-
-
- #pragma segment Main
- void Terminate()
- {
- WindowPtr aWindow;
- Boolean closed;
-
- CloseQueue(); // Clean up interaction with A/ROSE Prep
- closed = true;
- do {
- aWindow = FrontWindow(); // get the current front window
- if (aWindow != nil)
- closed = DoCloseWindow(aWindow); // close this window
- }
- while (closed && (aWindow != nil));
- if (closed)
- ExitToShell(); // exit if no cancellation
- } //Terminate
-
-
-
- #pragma segment Initialize
- void Initialize()
- {
- Handle menuBar;
- Ptr windowP;
- long total, contig;
- EventRecord event;
- short count, result;
-
- gInBackground = false;
- gSleepVal = 0;
- gSent = 0;
-
- InitGraf((Ptr) &qd.thePort);
- InitFonts();
- InitWindows();
- InitMenus();
- TEInit();
- InitDialogs(nil);
- InitCursor();
-
- // This next bit of code is necessary to allow the default button of our
- // alert be outlined.
-
- for (count = 1; count <= 3; count++)
- EventAvail(everyEvent, &event);
-
- SysEnvirons(kSysEnvironsVersion, &gMac);
-
- if (gMac.machineType < 0)
- BigBadError(eWrongMachine);
-
- if (! TrapAvailable(_WaitNextEvent, ToolTrap))
- BigBadError(eWrongMachine);
-
- if ((long) GetApplLimit() - (long) ApplicZone() < kMinHeap)
- BigBadError(eSmallSize);
-
- // ZeroScrap();
-
- PurgeSpace(&total, &contig);
- if (total < kMinSpace)
- BigBadError(eNoMemory);
-
- result = AROSEPrep();
- if (result != noErr)
- BigBadError(result);
-
- windowP = NewPtr(sizeof(WindowRecord));
- if ( windowP == nil )
- BigBadError(eNoWindow);
-
- gMyWindow = GetNewWindow(rWindow, windowP, (WindowPtr) -1);
- if ( gMyWindow == nil )
- BigBadError(eNoWindow);
-
- menuBar = GetNewMBar(rMenuBar); // read menus into menu bar
- if ( menuBar == nil )
- BigBadError(eNoMemory);
- SetMenuBar(menuBar); // install menus
- DisposHandle(menuBar);
- AddResMenu(GetMHandle(mApple), 'DRVR'); // add DA names to Apple menu
- DrawMenuBar();
-
- } //Initialize
-
-
- #pragma segment Main
- Boolean IsAppWindow(window)
- WindowPtr window;
- {
- short windowKind;
-
- if ( window == nil )
- return false;
- else { // application windows have windowKinds = userKind (8)
- windowKind = ((WindowPeek) window)->windowKind;
- return (windowKind = userKind);
- }
- } //IsAppWindow
-
-
- #pragma segment Main
- Boolean IsDAWindow(window)
- WindowPtr window;
- {
- if ( window == nil )
- return false;
- else // DA windows have negative windowKinds
- return ((WindowPeek) window)->windowKind < 0;
- } //IsDAWindow
-
-
- #pragma segment Initialize
- Boolean TrapAvailable(tNumber,tType)
- short tNumber;
- TrapType tType;
- {
- if ( ( tType == ToolTrap ) &&
- ( gMac.machineType > envMachUnknown ) &&
- ( gMac.machineType < envMacII ) ) { // it's a 512KE, Plus, or SE
- tNumber = tNumber & 0x03FF;
- if ( tNumber > 0x01FF ) // which means the tool traps
- tNumber = _Unimplemented; // only go to 0x01FF
- }
- return NGetTrapAddress(tNumber, tType) != GetTrapAddress(_Unimplemented);
- } //TrapAvailable
-
-
- #pragma segment Main
- void AlertUser( short error)
- {
- short itemHit;
- Str255 errMsg;
-
- SetCursor(&qd.arrow);
- if ((error>0)&&(error<=kLastErrStr)) {
- GetIndString(errMsg, rErrStrings, error);
- ParamText(errMsg, "", "", "");
- }
- else {
- NumToString(error, &errMsg);
- ParamText("\pUnknown error", errMsg, "", "");
- }
-
- itemHit = Alert(rUserAlert, nil);
- } // AlertUser
-
- #pragma segment Main
- void BigBadError( short error)
- {
- AlertUser(error);
- if (gTID>0)
- CloseQueue();
- ExitToShell();
- }
-
-
- #pragma segment Main
- void NumToHex( long n, short d, char *s) // I hate this @#%@ !
- // s must point to at least d+1 free bytes - returns Pascal String of length d
- // requires d > 0
- {
- short c;
-
- s[0] = d;
- do {
- c = (n & 0x0F) + 48; // not so Script Manager compatible
- // (as usual at this programming level...)
- if (c>57)
- c = c+7;
- s[d--] = (char) c;
- n = n>>4;
- } while (d > 0);
- }
-
- #pragma segment Main
- void StringCopy(char *s, char *t)
- {
- short n= (*t++ = *s++);
- while (n-- >0)
- *t++ = *s++;
- }
-
- #pragma segment Initialize
- short AROSEPrep()
- {
- StringHandle sh;
- Str255 taskName = "?", taskType = "?";
-
- sh = GetString(rTaskName);
- if (sh != nil)
- StringCopy(*sh,taskName);
- sh = GetString(rTaskType);
- if (sh != nil)
- StringCopy(*sh,taskType);
-
- gTID = OpenQueue(0);
- if (gTID == 0) {
- return(eNoAROSE);
- }
- if (!Register_Task (p2cstr(&taskName), p2cstr(&taskType), Machine_Visible)) {
- CloseQueue(); // better clean up - we are going to Exit
- return(eRegister);
- }
- return(noErr);
- }
-
-
- #pragma segment Main
- void TaskProcessing()
-
- // the only differences between an A/ROSE task and a .IPC process under MacOS are:
- // 1) a 5th parameter in Receive (here =nil: no completion routine)
- // 2) replace OS_NO_TIMEOUT (4th parameter) by -1L = "return immediately"
- // with m = nil or mMessage *m
- // 3) add a test on (m == 0)
- // 4) some minor adaptations in the declaration of variables
- // and in the initialisation
- //-------------------------------------------------------------------------
- {
- struct MBparms {
- short nmax; // max. depth of iteration
- short d; // corresponding to coord. distance between pixels
- short cx, cy; // current point of the complex plane to be computed
- short yMCP; // line number (to be sent back to server)
- };
-
- struct MBparms MBp; // these are the first 8 bytes of MBvariables, passed
- // along in m->mSData[0..1];
- short pixcnt, i;
- mMessage *m;
- char *pixStorage, *p;
- GrafPtr savePort;
-
-
- m = Receive(0L, 0L, 0L, -1L, nil); // -1L: return without waiting (OS_NO_TIMEOUT)
- // nil: no completion routine
-
- // in A/ROSE this would be: m = Receive(OS_MATCH_ALL, OS_MATCH_ALL, OS_MATCH_ALL, OS_NO_TIMEOUT);
-
- if (m) {
-
- if (m->mStatus != 0) { // message was considered undeliverable
- AlertUser(eUndeliverable);
- FreeMsg(m); // of no use any more: give it back to A/ROSE
- }
- else {
- switch (m->mCode) {
- case MBCODE:
- BlockMove((char *)&m->mSData[0], (char *)&MBp, 12);
- pixcnt = 8 * m->mDataSize;
- p = AROSEGetMem(m->mDataSize);
- if (p) {
- pixStorage = p;
- for (i=0; i<m->mDataSize; i++) *p++ = 0; // clear it out
- for (i=0; i<pixcnt; i++) {
- if (ITER16(MBp.cx, MBp.cy, MBp.nmax) & 0x1) // compute fancy pattern
- myBitSet(pixStorage, i);
- MBp.cx += MBp.d;
- }
- m->mOData[0] = MBp.yMCP;
- m->mCode++; // and send it back
- SwapTID(m);
- NetCopy(m->mFrom, pixStorage, m->mTo, m->mDataPtr, m->mDataSize);
- Send (m);
- AROSEFreeMem(pixStorage);
- gSent++; // update counter display
- }
- else {
- AlertUser(eAROSEMemErr);
- m->mCode++; // send it back anyway
- SwapTID(m);
- Send (m);
- }
-
- break;
-
- default:
- AlertUser(eUnknownMsg);
- m->mCode++;
- m->mCode |= 0x8000; // unrecognized message code;
- m->mStatus = OS_UNKNOWN_MESSAGE; // defined in "managers.h"
- SwapTID(m);
- Send (m);
-
- break;
-
- }
-
- GetPort(&savePort);
- SetPort(gMyWindow);
-
- InvalRect(&(gMyWindow->portBits.bounds));
-
- SetPort(savePort);
-
- } // message OK
-
- } // a message arrived
- }
-
-
-
- void myBitSet(char *pixStorage, long i)
- {
- long offset;
- short bitnb;
- char abyte, *p;
-
- offset = (i >> 3); // divide /8
- bitnb = i - 8*offset;
- abyte = 0x80 >> bitnb;
- p = pixStorage + offset;
- *p = *p | abyte;
- }
-
-